/**
 * Project: guahao-portal-web-home
 * 
 * File Created at 2012-9-26
 * 
 * Copyright 2012 Greenline.com Corporation Limited.
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * Greenline Company. ("Confidential Information").  You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with Greenline.com.
 */
package com.hd.hdxgddcommon.utils;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @Type DateUtils
 * @Desc
 * @author jianyun.zheng
 * @date 2012-9-26
 * @Version V1.0
 */
public class DateUtils {
	
	private static final Logger logger = LoggerFactory.getLogger(DateUtils.class);
	
    public static final String FORMAT_YYYY_MM_DD = "yyyy-MM-dd";
    /** HH:mm:ss */
    public static String DEFAULT_TIME_FORMAT = "HH:mm:ss";
    public static final String FORMATYYYYMMDD = "yyyyMMdd";
    public static final String FORMAT_YYYY_MM = "yyyy-MM";
    public static final String DATE_FORMAT_YMDHMS = "yyyy-MM-dd HH:mm:ss";
    public static final String DATE_FORMAT_YMDHM = "yyyy-MM-dd HH:mm";
    public static final String DATE_FORMAT_TIMESTAMP = "yyyyMMddHHmmssSSS";
    /** yyyyMMddTHHmmssZ*/
    public static String DATE_TIME_FOR_LECHANGE = "yyyyMMdd'T'HHmmss'Z'";


    private static String[] weekDays = { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" };

    /**
     * 上下午数组
     */
    private final static String apms[] = { "上午", "下午", "晚上", "全天" };

    /**
     * getTimeIntervalSecond 时间格式控制器
     */
    public static SimpleDateFormat timeIntervalSecondFormatter = new SimpleDateFormat(DATE_FORMAT_YMDHMS);


    /**
     * 获得i秒后的时间
     * @param i 负数表示time这个时间之前多少s
     * @return
     */
    public static Date getTimeIntervalSecond(LocalDateTime time,long i) {

        ZoneId zoneId = ZoneId.systemDefault();
        LocalDateTime localDateTime = time.plusSeconds(i);
        ZonedDateTime zdt = localDateTime.atZone(zoneId);
        return Date.from(zdt.toInstant());
    }
    /**
     * 获得i秒后的时间
     * @param i 负数表示当前时间之前多少s
     * @return
     */
    public static String getTimeIntervalSecond(long i) {
        LocalDateTime now = LocalDateTime.now();

        ZoneId zoneId = ZoneId.systemDefault();
        LocalDateTime localDateTime = now.plusSeconds(i);
        ZonedDateTime zdt = localDateTime.atZone(zoneId);
        Date date = Date.from(zdt.toInstant());
        return timeIntervalSecondFormatter.format(date);
    }

    public interface DAY_SECTION {
        /**
         * 上午
         */
        public Integer APM_AM = 1;
        /**
         * 下午
         */
        public Integer APM_PM = 2;
        /**
         * 晚上
         */
        public Integer APM_NT = 3;
        /**
         * 全天
         */
        public Integer APM_FL = 4;
    }

    /**
     * 获取指定日期所在的周期序号，从0开始（当前日期的下一天为周期的起始日期，7天为一个周期，即一周）
     * 
     * @param date 格式为yyyy-MM-dd的日期
     * @return 0、1、2...
     */
    public static int getIndexOfCycle(String date) {
        try {
            SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
            Calendar cal = Calendar.getInstance();
            cal.setTime(df.parse(date));
            int b = getDays(new Date(), cal.getTime());
            int a = -1;
            if ((b % 7) == 0) {
                a = (b / 7) - 1;
            } else {
                a = b / 7;
            }
            return a;
        } catch (Exception e) {
        	logger.error("获取指定日期所在的周期序号出错",e);
        }
        return -1;
    }

    /**
     * 获取指定日期所在的周期中的序号，从0开始（当前日期的下一天为周期的起始日期，7天为一个周期，即一周）
     * 
     * @param date
     * @return int
     */
    public static int getIndexInCycle(String date) {
        try {
            SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
            Calendar cal = Calendar.getInstance();
            cal.add(Calendar.DAY_OF_YEAR, 1); // 第二天
            int d = cal.get(Calendar.DAY_OF_WEEK); // 星期几
            cal.setTime(df.parse(date));
            int id = cal.get(Calendar.DAY_OF_WEEK); // 输入日期的星期几
            int idx = id - d;
            idx = idx < 0 ? idx + 7 : idx; // 一周有7天
            return idx;
        } catch (Exception e) {
            logger.error("异常：{}",e);
        }
        return -1;
    }

    /**
     * 
     * @param oldFormatDate
     * @param type
     * @return int
     */
    public static String getNewFormatDate(String type, String oldFormatDate) {
        if (DATE_FORMAT_TIMESTAMP.equals(type)) {
            oldFormatDate = oldFormatDate.substring(0, 4) + "-" + oldFormatDate.substring(4, 6) + "-"
                    + oldFormatDate.substring(6, 8) + " " + oldFormatDate.substring(8, 10) + ":"
                    + oldFormatDate.substring(10, 12) + ":" + oldFormatDate.substring(12, 14);
        }
        return oldFormatDate;
    }

    /**
     *
     * @return int
     */
    public static String getNewYMDFormatDate(String dateStr) {
        try {
            dateStr = dateStr.substring(0, 4) + "-" + dateStr.substring(4, 6) + "-"
                    + dateStr.substring(6, 8);
            return dateStr;
        } catch (Exception e) {
            logger.error("异常：{}",e);
            return dateStr;
        }
    }

    /**
     * 计算两个日期的差距(天数)，去掉时分秒
     * 
     * @param date1
     * @param date2
     * @return Long
     */
    public static int getDays(Date date1, Date date2) {
        Long d1 = getYmdTime(date1).getTime() / 1000;
        Long d2 = getYmdTime(date2).getTime() / 1000;
        Long result =(d2 - d1) / (24 * 3600);
        return Integer.valueOf(result.toString());
    }

    /**
     * 计算两个时间相差多少分钟
     * 
     * @param startDate
     * @param endDate
     * @return
     */
    public static long getMinutes(Date startDate, Date endDate) {

        // 毫秒ms
        long diff = endDate.getTime() - startDate.getTime();
        return diff / (60 * 1000);
    }

    /**
     * 去掉时分秒
     * 
     * @param date
     * @return Date
     */
    public static Date getYmdTime(Date date) {
        if (date == null) {
            return (new Date());
        }
        Calendar day = Calendar.getInstance();
        day.setTime(date);
        day.set(Calendar.HOUR_OF_DAY, 0);
        day.set(Calendar.MINUTE, 0);
        day.set(Calendar.SECOND, 0);
        day.set(Calendar.MILLISECOND, 0);
        Date convertTime = day.getTime();
        return convertTime;
    }

    /**
     * 
     * 获取年月日时分秒
     * 
     * @param date
     * @return Date
     */
    public static Date getYmdHms(Date date) {
        if (date == null) {
            return (new Date());
        }
        Calendar day = Calendar.getInstance();
        day.setTime(date);
        day.set(Calendar.HOUR_OF_DAY, 23);
        day.set(Calendar.MINUTE, 59);
        day.set(Calendar.SECOND, 59);
        Date convertTime = day.getTime();
        return convertTime;
    }

    /**
     * 根据时间类型获得上/下午
     * 
     * @param timeType
     * @return
     */
    public static String getApmByTimeType(Integer timeType) {
        String apm = "";
        if (timeType == null) {
            return "";
        }
        if (DAY_SECTION.APM_AM.equals(timeType)) {
            apm = apms[0];
        } else if (DAY_SECTION.APM_PM.equals(timeType)) {
            apm = apms[1];
        } else if (DAY_SECTION.APM_NT.equals(timeType)) {
            apm = apms[2];
        } else if (DAY_SECTION.APM_FL.equals(timeType)) {
            apm = apms[3];
        }
        return apm;
    }

    /**
     * 根据上/下午获得时间类型
     * 
     * @param time
     * @return
     */
    public static Integer getTimeTypeByTime(String time) {
        int type = 4;
        if (StringUtils.isEmpty(time)) {
            return type;
        }
        if (time.contains(apms[0])) {
            type = 1;
        } else if (time.contains(apms[1])) {
            type = 2;
        } else if (time.contains(apms[2])) {
            type = 3;
        } else if (time.contains(apms[3])) {
            type = 4;
        }
        return type;
    }

    /**
     * 获取下一年份 第一天
     * @param nextYear 年份
     * @return 下一年份第一天 格式为yyyy-MM-dd
     */
    public static String getNextYear(Integer nextYear){
        Calendar calendar = Calendar.getInstance();
        calendar.clear();
        calendar.set(Calendar.YEAR, nextYear);
        Date nextYearFirst = calendar.getTime();

        return formatDate(nextYearFirst,"yyyy-MM-dd");
    }

    /**
     * 获取日期，格式为yyyy年MM月dd日
     * 
     * @author wangbiao
     * @param d
     * @return String
     */
    public static String getDateYmd(Date d) {
        return getDateFormat(d, FORMAT_YYYY_MM_DD);
    }

    public static String getDateFormat(Date d, String format) {
        if (d == null || StringUtils.isBlank(format)) {
            return "";
        }
        SimpleDateFormat destsmf = new SimpleDateFormat(format);
        return destsmf.format(d);
    }

    /**
     * 短日期转变成长日期 20120102 转换成 2012-01-02
     * 
     * @param theDate
     * @return
     */
    public static String convertShortDate(String theDate) {
        if (StringUtils.isNotBlank(theDate) && theDate.length() == 8) {
            return theDate.substring(0, 4) + "-" + theDate.substring(4, 6) + "-" + theDate.substring(6, 8);
        }
        return StringUtils.EMPTY;
    }

    /**
     * 字符串转换为日期
     * 
     * @throws ParseException
     */
    public static Date getStringToDate(String date) throws ParseException {
        return new SimpleDateFormat("yyyyMMdd").parse(date);
    }

    /**
     * 用yyyyMMdd来格式化日期字符串
     *
     * @param s
     * @return 如果s==null或者格式异常，返回null
     */
    public static Date getYyyyMMddDate(String s) {
        return getDateByFormat(DATE_FORMAT_YMDHMS, s);
    }

    /**
     * 用yyyy-MM-dd来格式化日期字符串
     *
     * @param format
     * @return 如果s==null或者格式异常，返回null
     */
    public static Date getDateByFormat(String format, String dateStr) {
        if (StringUtils.isBlank(dateStr)) {
            return null;
        }
        try {
            return new SimpleDateFormat(format).parse(dateStr);
        } catch (ParseException e) {
            return null;
        }
    }

    /**
     * 把字符串转换为相应日期
     *
     * @param theDate
     * @param format
     * @return
     */
    public static Date strCovertDate(String theDate, String format) {

        SimpleDateFormat sdf = new SimpleDateFormat(format);
        try {
            return sdf.parse(theDate);
        } catch (ParseException e) {
            logger.error("String字符串转化为日期类型失败，theDate=" + theDate + "，format=" + format, e);
            return null;
        }
    }

    /**
     * 获取日期指定的格式的字符串
     * 
     * @param date
     * @param pattern
     * @return Date 对象类型字符串形式
     */
    public static String formatDate(Date date, String pattern) {
        if (null != date) {
            DateFormat dateFomat = new SimpleDateFormat(pattern);
            return dateFomat.format(date);
        }
        return "";
    }

    /**
     * 包含时分秒的date类型
     * 
     * @param date
     * @return Date
     */
    public static Date getYmdHmsDate(Date date) {
        DateFormat dateFomat = new SimpleDateFormat(DATE_FORMAT_YMDHMS);
        String dateStr = dateFomat.format(date);
        try {
            return dateFomat.parse(dateStr);
        } catch (ParseException e) {
            return null;
        }
    }

    /**
     * 获取当前日期是星期几
     * 
     * @param date
     * @return 当前日期是星期几
     */
    public static String getWeekOfDate(Date date) {
        if (date == null) {
            return "";
        }
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
        if (w < 0)
            w = 0;
        return weekDays[w];
    }

    /**
     * 根据周几动态计算当前周的排班的日期
     * 
     * @param weekday 1 周一， 2 周二 。。。7 周日
     * @return
     */
    public static String getDate(Integer weekday) {
        String date = null;
        if (null == weekday || weekday < 1 || weekday > 7) {
        	logger.error("静态排班的weekday值不在正常范围内，请检查：[" + weekday + "]");
        } else {
            int d = weekday.intValue();
            d = d % 7 + 1; // Calendar类中周日为第一天，即1 周日， 2 周一 。。。7 周六，需要进行转换
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
            Calendar c = Calendar.getInstance();
            int nd = c.get(Calendar.DAY_OF_WEEK); // 当天的周期序号
            c.set(Calendar.DAY_OF_WEEK, d);
            if (d <= nd) { // 当天之前的（包括当天），取下周的这天
                c.add(Calendar.WEEK_OF_MONTH, 1);
            }
            date = sdf.format(c.getTime());
        }
        return date;
    }

    /**
     * 取得医院放号时间
     * 
     * @param reserveOpentime
     */
    public static String getOpenTime(String reserveOpentime) {
        if ("00:00".equals(reserveOpentime)) {
            return reserveOpentime;
        }

        String openTime = StringUtils.EMPTY;
        try {
            if (StringUtils.isNotBlank(reserveOpentime)) {
                SimpleDateFormat osdf = new SimpleDateFormat("HHmm");
                SimpleDateFormat nsdf = new SimpleDateFormat("HH:mm");
                try {
                    openTime = nsdf.format(osdf.parse(reserveOpentime));
                } catch (ParseException e) {
                	logger.error("获取放号时间异常：", e);
                }
            }
        } catch (Exception e) {
        	logger.error("获取放号时间异常：", e);
        }
        openTime = "".equals(openTime) ? "00:00" : openTime;

        return openTime;
    }

    /**
     * 用yyyy-MM-dd T HH:mm:ss Z来格式化日期字符串
     * 
     * @param s
     * @return 如果s==null或者格式异常，返回null
     */
    public static Date getYyyyMMddTZDate(String s) {
        if (s == null) {
            return null;
        }
        try {
            return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").parse(s);
        } catch (ParseException e) {
        	logger.error("格式转化错误，string=" + s, e);
            return null;
        }
    }

    // 时间描述 1天是 24*3600*1000毫秒
    public static String getTimeDesc(Date date) {
        if (null == date) {
            return null;
        }
        Calendar now = Calendar.getInstance();
        Calendar time = Calendar.getInstance();
        time.setTime(date);
        // 毫秒偏移量
        long t = (now.getTimeInMillis() - time.getTimeInMillis()) / 1000;
        // 昨天以前的，直接显示日期，如2012-01-08，如果有多余空间，显示日期及时间2012-01-08 09:20
        if ((t < 0)
                || (t > ((now.get(Calendar.HOUR_OF_DAY) + 24) * 3600 + now.get(Calendar.MINUTE) + 60 + now
                .get(Calendar.SECOND))) || (t < 0)) {
            SimpleDateFormat df = new SimpleDateFormat("yyyy/MM/dd");
            return df.format(date);
        }

        // 1个小时以上，但还在今天内，显示为"今天 09:30"
        if (t > 3600) {
            SimpleDateFormat df = new SimpleDateFormat("HH:mm");
            String str = df.format(date);
            int day_time = time.get(Calendar.DAY_OF_YEAR);// 评论的天
            int now_time = now.get(Calendar.DAY_OF_YEAR);// 当前天

            // 1个小时以上，但在昨天内，显示为"昨天11:59"
            if (day_time < now_time) {
                str = "昨天 ".concat(str);
            } else {
                str = "今天 ".concat(str);
            }
            return str;
        }
        // 1分钟到1个小时内，显示为"XX分钟前"
        if (t >= 60) {
            return t / 60 + "分钟前";
        }
        // 小于1分钟的为刚刚
        return "刚刚";
    }

    public static Date plusDay(Date date, int days){
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(Calendar.DAY_OF_YEAR, days);
        return c.getTime();
    }

    /**
     * 日期比较
     * @param date1 开始日期
     * @param date2 当前日期
     * @param date3 结束日期
     * @return
     */
    public static boolean compareDate(Date date1,Date date2,Date date3){
        if(date1==null){
            return false;
        }
        try {
            if (date1.getTime() > date2.getTime()||date3.getTime()<date2.getTime()) {
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 指定时间所在一周的周一和周日时间
     * @param time 指定时间
     * @return
     */
    public static Map<String,String> getWeekDate(Date time) {
        Map<String,String> map = new HashMap();
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd"); //设置时间格式
        Calendar cal = Calendar.getInstance();
        cal.setTime(time);

        //判断要计算的日期是否是周日，如果是则减一天计算周六的，否则会出问题，计算到下一周去了
        int dayWeek = cal.get(Calendar.DAY_OF_WEEK);//获得当前日期是一个星期的第几天
        if(1 == dayWeek) {
            cal.add(Calendar.DAY_OF_MONTH, -1);
        }
        cal.setFirstDayOfWeek(Calendar.MONDAY);//设置一个星期的第一天，按中国的习惯一个星期的第一天是星期一
        int day = cal.get(Calendar.DAY_OF_WEEK);//获得当前日期是一个星期的第几天
        cal.add(Calendar.DATE, cal.getFirstDayOfWeek()-day);//根据日历的规则，给当前日期减去星期几与一个星期第一天的差值
        String weekBegin = sdf.format(cal.getTime());

        cal.add(Calendar.DATE, 6);
        String weekEnd = sdf.format(cal.getTime());
        map.put("mondayDate",weekBegin);
        map.put("sundayDate",weekEnd);
        return map;
    }

    /**
     * 指定时间所在一周的周一和周日时间
     * @param time 指定时间
     * @return
     */
    public static Map<String,String> getAfterWeekDate(Date time) {
        Map<String,String> map = new HashMap();
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd"); //设置时间格式
        Calendar cal = Calendar.getInstance();
        cal.setTime(time);

        //判断要计算的日期是否是周日，如果是则减一天计算周六的，否则会出问题，计算到下一周去了
        int dayWeek = cal.get(Calendar.DAY_OF_WEEK);//获得当前日期是一个星期的第几天
        if(1 == dayWeek) {
            cal.add(Calendar.DAY_OF_MONTH, -1);
        }
        cal.setFirstDayOfWeek(Calendar.MONDAY);//设置一个星期的第一天，按中国的习惯一个星期的第一天是星期一
        int day = cal.get(Calendar.DAY_OF_WEEK);//获得当前日期是一个星期的第几天
        cal.add(Calendar.DATE, cal.getFirstDayOfWeek()-day);//根据日历的规则，给当前日期减去星期几与一个星期第一天的差值
        cal.add(Calendar.DATE, 7);
        String weekBegin = sdf.format(cal.getTime());

        cal.add(Calendar.DATE, 6);
        String weekEnd = sdf.format(cal.getTime());
        map.put("mondayDate",weekBegin);
        map.put("sundayDate",weekEnd);
        return map;
    }

    /**
     * Adds a number of years to a date returning a new object.
     * The original {@code Date} is unchanged.
     *
     * @param date  the date, not null
     * @param amount  the amount to add, may be negative
     * @return the new {@code Date} with the amount added
     * @throws IllegalArgumentException if the date is null
     */
    public static Date addYears(final Date date, final int amount) {
        return add(date, Calendar.YEAR, amount);
    }

    public static Date addMonths(final Date date, final int amount) {
        return add(date, Calendar.MONTH, amount);
    }

    public static Date add(final Date date, final int calendarField, final int amount) {
        if (date == null) {
            throw new IllegalArgumentException("The date must not be null");
        }
        final Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(calendarField, amount);
        return c.getTime();
    }

    /**
     * date2比date1多的天数
     * @param date1
     * @param date2
     * @return
     */
    public static int differentDays(Date date1,Date date2)
    {
        Calendar cal1 = Calendar.getInstance();
        cal1.setTime(date1);

        Calendar cal2 = Calendar.getInstance();
        cal2.setTime(date2);
        int day1= cal1.get(Calendar.DAY_OF_YEAR);
        int day2 = cal2.get(Calendar.DAY_OF_YEAR);

        int year1 = cal1.get(Calendar.YEAR);
        int year2 = cal2.get(Calendar.YEAR);
        if(year1 != year2)   //同一年
        {
            int timeDistance = 0 ;
            for(int i = year1 ; i < year2 ; i ++)
            {
                if(i%4==0 && i%100!=0 || i%400==0)    //闰年
                {
                    timeDistance += 366;
                }
                else    //不是闰年
                {
                    timeDistance += 365;
                }
            }

            return timeDistance + (day2-day1) ;
        }
        else    //不同年
        {
            return day2-day1;
        }
    }


    /**
     * 将日期转换成指定格式的字符串
     * @param date - 要转换的日期
     * @param dateFormat - 日期格式
     * @return String 日期对应的字符串
     */
    public static String convertDate2String(Date date, String dateFormat) {
        if (date == null) {
            return "";
        }
        SimpleDateFormat sdf;
        if(dateFormat != null && !dateFormat.equals("")) {
            try {
                sdf = new SimpleDateFormat(dateFormat);
            } catch(Exception e) {
                sdf = new SimpleDateFormat(FORMAT_YYYY_MM_DD+" "+DEFAULT_TIME_FORMAT);
            }
        } else {
            sdf = new SimpleDateFormat(FORMAT_YYYY_MM_DD+" "+DEFAULT_TIME_FORMAT);
        }
        return sdf.format(date);
    }


}
